package com.taobao.library;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;


/**
 * Description:
 * <p>
 * Created by rowandjj(chuyi)<br/>
 * Date: 16/1/6<br/>
 * Time: 下午4:50<br/>
 */
@SuppressWarnings("unused")
public class VerticalBannerView extends LinearLayout implements BaseBannerAdapter.OnDataChangedListener {

    private float mBannerHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 40, getResources().getDisplayMetrics());
    private int mGap = 4000;
    private int mDefaultTextSize = 18;
    private int mAnimDuration = 1000;

    private BaseBannerAdapter mAdapter;

    private View mFirstView;
    private View mSecondView;

    private int mPosition;

    private boolean isStarted;
    private Paint mDebugPaint;

    SpannableString mData;
    private int flag = 0;

    public VerticalBannerView(Context context) {
        this(context, null);
    }

    public VerticalBannerView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public VerticalBannerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs, defStyleAttr);
    }


    /**
     * bannerHeight banner的高度
     * animDuration 每次切换动画时间
     * gap banner切换时间
     */
    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
        setOrientation(VERTICAL);
        mDebugPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.VerticalBannerView);
        mGap = array.getInteger(R.styleable.VerticalBannerView_gap, mGap);
        mDefaultTextSize = array.getInteger(R.styleable.VerticalBannerView_defaultTextSize, mDefaultTextSize);
        mAnimDuration = array.getInteger(R.styleable.VerticalBannerView_animDuration, mAnimDuration);

        if (mGap <= mAnimDuration) {
            mGap = 4000;
            mAnimDuration = 1000;
        }

        array.recycle();
    }

    /**
     * 设置banner的数据
     */
    public void setAdapter(BaseBannerAdapter adapter) {
        if (adapter == null) {
            throw new RuntimeException("adapter must not be null");
        }
        if (mAdapter != null) {
            throw new RuntimeException("you have already set an Adapter");
        }
        this.mAdapter = adapter;
        mAdapter.setOnDataChangedListener(this);
        setupAdapter();
    }

    public void start() {
        if (mAdapter == null) {
            throw new RuntimeException("you must call setAdapter() before start");
        }

        if (!isStarted && mAdapter.getCount() > 1) {
            isStarted = true;
            post/*Delayed*/(mRunnable/*, mGap*/);
        }
    }

    public void stop() {
        removeCallbacks(mRunnable);
        isStarted = false;
    }


    private void setupAdapter() {
        removeAllViews();

        if (mAdapter.getCount() == 1) {
            mFirstView = mAdapter.getView(this);
            mAdapter.setItem(mFirstView, mAdapter.getItem(0));
            addView(mFirstView);
        } else {
            mFirstView = mAdapter.getView(this);
            mSecondView = mAdapter.getView(this);
            mAdapter.setItem(mFirstView, mAdapter.getItem(0));
            mAdapter.setItem(mSecondView, mAdapter.getItem(1));
            addView(mFirstView);
            addView(mSecondView);

            mPosition = 1;
            isStarted = false;
        }
        setBackgroundDrawable(mFirstView.getBackground());
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (LayoutParams.WRAP_CONTENT == getLayoutParams().height) {
            getLayoutParams().height = (int) mBannerHeight;
        } else {
            mBannerHeight = getHeight();
        }
        if (isInEditMode()) {
            setBackgroundColor(Color.GRAY);
            return;
        }
        if (mFirstView != null) {
            mFirstView.getLayoutParams().height = (int) mBannerHeight;
        }
        if (mSecondView != null) {
            mSecondView.getLayoutParams().height = (int) mBannerHeight;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (isInEditMode()) {
            mDebugPaint.setColor(Color.WHITE);
            mDebugPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
            mDebugPaint.setStyle(Paint.Style.STROKE);
            canvas.drawText("banner is here", 20, getHeight() * 2 / 3, mDebugPaint);
        }
    }

    @Override
    public void onChanged() {
        setupAdapter();
    }


    private void performSwitch() {
        ObjectAnimator animator1 = ObjectAnimator.ofFloat(mFirstView, "translationY", 0, mFirstView.getTranslationY() - mBannerHeight);
        ObjectAnimator animator2 = ObjectAnimator.ofFloat(mSecondView, "translationY", 0, mSecondView.getTranslationY() - mBannerHeight);
        AnimatorSet set = new AnimatorSet();
        set.playTogether(animator1, animator2);
        set.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mFirstView.setTranslationY(0);
                mSecondView.setTranslationY(0);
                View removedView = getChildAt(0);
                mPosition++;
                mAdapter.setItem(removedView, mAdapter.getItem(mPosition % mAdapter.getCount()));
                removeView(removedView);
                addView(removedView, 1);
            }

        });
        set.setDuration(mAnimDuration);
        set.start();
    }

    private void backToFirst() {
        BaseBannerAdapter adapter = mAdapter;
        mAdapter = null;
        setAdapter(adapter);

    }

    private AnimRunnable mRunnable = new AnimRunnable();


    private class AnimRunnable implements Runnable {

        @Override
        public void run() {
            performSwitch();
            postDelayed(this, mGap);
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        stop();
    }

    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }


    //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


    public void reset() {
        //stop();
        mAdapter = null;
        setData(mData);
        stop();
//        int current = mPosition % mAdapter.getCount();
//        if (current != 0) {
//            backToFirst();
//        }
    }

    public void setData(final SpannableString notice) {
        mData = notice;
//        getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
//            @Override
//            public void onGlobalLayout() {
//                getViewTreeObserver().removeGlobalOnLayoutListener(this);
//                //startWithFixedWidth(notice, getWidth());
//                startWithFixedWidthSpannables(notice, getWidth());
//            }
//        });
        post(new Runnable() {
            @Override
            public void run() {
                startWithFixedWidthSpannables(notice, getWidth());
            }
        });
    }

    public void setData(final String notice) {
        setData(new SpannableString(notice));
    }


    public class DefaultModel {
        public SpannableString title;
        public String url;

        public DefaultModel(SpannableString title, String url) {
            this.title = title;
            this.url = url;
        }
    }

    public class DefaultAdapter extends BaseBannerAdapter<DefaultModel> {

        private List<DefaultModel> mDatas;


        public DefaultAdapter(List<DefaultModel> datas) {
            super(datas);
        }

        @Override
        public View getView(VerticalBannerView parent) {
            return LayoutInflater.from(parent.getContext()).inflate(R.layout.item_default, null);
        }

        @Override
        public void setItem(final View view, final DefaultModel data) {
            TextView tv = (TextView) view.findViewById(R.id.tv_01);
            tv.setText(data.title);
            //你可以增加点击事件
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //比如打开url
                    //Toast.makeText(view.getContext(), data.url, Toast.LENGTH_SHORT).show();
                    if (flag == 0) {
                        start();
                        Toast.makeText(view.getContext(), "restart", Toast.LENGTH_SHORT).show();
                        flag = 1;
                    } else {
                        reset();
                        Toast.makeText(view.getContext(), "reset", Toast.LENGTH_SHORT).show();
                        flag = 0;
                    }
                }
            });
        }
    }

    /**
     * 这个方法可以处理多个ForegroundColorSpan
     * 根据宽度和公告字符串启动轮播
     */
    private void startWithFixedWidthSpannables(SpannableString notice, int width) {
        float mLines = 2.0f;
        List<SpannableString> notices = new ArrayList<>();
        int noticeLength = notice.length();
        int dpW = px2dip(getContext(), width);
        int limit = dpW / mDefaultTextSize;
        if (dpW == 0) {
            throw new RuntimeException("Please set MarqueeView width !");
        }
        notices.clear();
        if (noticeLength <= limit) {
            notices.add(notice);
        } else {
            int size = noticeLength / limit + (noticeLength % limit != 0 ? 1 : 0);
            size = (int) Math.ceil(size / mLines);
            ForegroundColorSpan[] spans = notice.getSpans(0, notice.length(), ForegroundColorSpan.class);
            if (spans != null && spans.length > 0) {
                //Timber.e("SpanStart=" + highLightEndOrigin + ",SpanStart=" + highLightEndOrigin);
                for (int i = 0; i < size; i++) {
                    //子串
                    int subStartIndex = (int) (i * (limit * mLines));
                    int subEndIndex = (i + 1) * (limit * mLines) >= noticeLength ? noticeLength : (int) ((i + 1) * (limit * mLines));

                    String sub = notice.toString().substring(subStartIndex, subEndIndex);
                    SpannableString subS = getSubSpannableString(notice, sub);
                    notices.add(subS);
                }
            } else {
                for (int i = 0; i < size; i++) {
                    int startIndex = (int) (i * (limit * mLines));
                    int endIndex = (i + 1) * (limit * mLines) >= noticeLength ? noticeLength : (int) ((i + 1) * (limit * mLines));
                    notices.add(new SpannableString(notice.toString().substring(startIndex, endIndex)));
                }
            }
        }
        setDefaultAdapter(notices);
    }

    private void setDefaultAdapter(List<SpannableString> notices) {
        List<DefaultModel> datas = new ArrayList<>();
        for (SpannableString item : notices) {
            datas.add(new DefaultModel(item, item.toString()));
        }
        if (mAdapter == null) {
            final DefaultAdapter adapter = new DefaultAdapter(datas);
            setAdapter(adapter);
            //start();
        }
    }

    // 将px值转换为dip或dp值，保证尺寸大小不变
    public static int px2dip(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

    private SpannableString getSubSpannableString(SpannableString spannableString, String subStr) {
        ArrayList<SpanE> targetSpanEs = new ArrayList<SpanE>();
        ArrayList<SpanE> spanEs = new ArrayList<SpanE>();
        ForegroundColorSpan[] spans = spannableString.getSpans(0, spannableString.length(), ForegroundColorSpan.class);

        for (ForegroundColorSpan item : spans) {
            spanEs.add(new SpanE(spannableString.getSpanStart(item), spannableString.getSpanEnd(item), item.getForegroundColor()));
        }

        int subIndex = spannableString.toString().indexOf(subStr);
        SubSpanStrE sub = new SubSpanStrE(subIndex, subIndex + subStr.length());

        for (SpanE item : spanEs) {
            int[] check = check(new int[]{item.start, item.end}, new int[]{sub.start, sub.end});
            boolean has = check[1] != 0;
            if (has) {
                targetSpanEs.add(new SpanE(check[0], check[1], item.color));
            }
        }
//        for (SpanE target : targetSpanEs) {
//            Log.e(TAG, "[" + target.start + "," + target.end + "]");
//        }

        for (SpanE target : targetSpanEs) {
            target.start = Math.max(target.start, sub.start);
            target.end = Math.min(target.end, sub.end);
        }

//        for (SpanE target : targetSpanEs) {
//            Log.e(TAG, "[" + target.start + "," + target.end + "]");
//        }

        SpannableString spannable = new SpannableString(subStr);
        for (SpanE target : targetSpanEs) {
            int startIndex = target.start - sub.start;
            int endIndex = target.end - sub.start;
            spannable.setSpan(new ForegroundColorSpan(target.color),
                    startIndex,
                    endIndex,
                    Spanned.SPAN_INCLUSIVE_INCLUSIVE);//高亮
        }

        return spannable;

    }

    /**
     * 求相同区间
     *
     * @param a
     * @param b
     * @return
     */
    private int[] check(int[] a, int[] b) {
        int[] result = new int[2];
        if (a[1] > b[0]) {
            if (a[0] > b[0]) {
                if (a[0] > b[1]) {
                    return result;
                } else {
                    result[0] = a[0];
                }
            } else {
                result[0] = b[0];
            }
            //较小者
            result[1] = Math.min(a[1], b[1]);
            return result;
        }//else无交集
        if (a[0] < b[0]) {
            if (b[0] <= a[1]) {
                result[0] = b[0];
                result[1] = a[1];
            }
        } else {
            result[0] = a[0];
            //较小者
            result[1] = Math.min(a[1], b[1]);
        }
        return result;
    }

    private class SpanE {
        int start, end;
        int color;

        public SpanE(int start, int end, int color) {
            this.start = start;
            this.end = end;
            this.color = color;
        }
    }

    private class SubSpanStrE {
        int start, end;

        public SubSpanStrE(int start, int end) {
            this.start = start;
            this.end = end;
        }
    }
}
















